///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
*	Contains AABB-related code. (axis-aligned bounding box)
*	\file		LaborAABB.h
*	\author		Pierre Terdiman
*	\date		January, 13, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __LABORAABB_H__
#define __LABORAABB_H__


#include "LaborMathDecl.h"
#include "LaborRay.h"
#include "../LaborCoreDef.h"
NAMESPACE_LABOR3D_BEGIN
// Forward declarations
class CLSphere;

const float Eps = 1E-5f;
const float Inf = 1E10;

//! Declarations of type-independent methods (most of them implemented in the .cpp)
#define AABB_COMMON_METHODS																											\
	CLAABB&			add(const CLAABB& aabb);																					\
	float			makeCube(CLAABB& cube)																			const;	\
	void			makeSphere(CLSphere& sphere)																		const;	\
	const char*		computeOutline(const CLPoint3& local_eye, int& num)												const;	\
	float			computeBoxArea(const CLPoint3& eye, const CLMatrix4x4& mat, float width, float height, int& num)	const;	\
	bool			isInside(const CLAABB& box)																		const;	\
	bool			computePlanes(CLPlane* planes)																	const;	\
	bool			computePoints(CLPoint3* pts)																		const;	\
	const CLPoint3*	getVertexNormals()																				const;	\
	const unsigned int*		getEdges()																						const;	\
	const CLPoint3*	getEdgeNormals()																				const;	\
	inline	bool			containsPoint(const CLPoint3& p)																	const	\
{																										\
	if(p.x > getMax(0) || p.x < getMin(0)) return false;												\
	if(p.y > getMax(1) || p.y < getMin(1)) return false;												\
	if(p.z > getMax(2) || p.z < getMin(2)) return false;												\
	return true;																						\
}

enum AABBType
{
	EY_AABB_RENDER			= 0,	//!< AABB used for rendering. Not visible == not rendered.
	EY_AABB_UPDATE			= 1,	//!< AABB used for dynamic updates. Not visible == not updated.

	EY_AABB_FORCE_DWORD	= 0x7fffffff,
};

//#ifndef NOT_USE_MINMAX

struct xlShadowAABB
{
	CLPoint3	m_Min;
	CLPoint3	m_Max;
};

class LABORCORE_API CLAABB
{
public:
	//! Constructor
	inline						CLAABB()	{}
	//! Destructor
	inline						~CLAABB()	{}

	//! Type-independent methods
	AABB_COMMON_METHODS;

	void init(lscalar len = 1000000.0f)
	{
		m_Min.x = len;	m_Max.x = -len;
		m_Min.y = len;	m_Max.y = -len;
		m_Min.z = len;	m_Max.z = -len;
	}
	void addPoint(const CLPoint3& v)
	{
		if(v.x > m_Max.x) m_Max.x = v.x;
		if(v.y > m_Max.y) m_Max.y = v.y;
		if(v.z > m_Max.z) m_Max.z = v.z;

		if(v.x < m_Min.x) m_Min.x = v.x;
		if(v.y < m_Min.y) m_Min.y = v.y;
		if(v.z < m_Min.z) m_Min.z = v.z;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Setups an AABB from min & max vectors.
	*	\param		min			[in] the min point
	*	\param		max			[in] the max point
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void		setMinMax(const CLPoint3& min, const CLPoint3& max)		{ m_Min = min;		m_Max = max;									}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Setups an AABB from center & extents vectors.
	*	\param		c			[in] the center point
	*	\param		e			[in] the extents vector
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void		setCenterExtents(const CLPoint3& c, const CLPoint3& e)	{ m_Min = c - e;		m_Max = c + e;								}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Setups an empty AABB.
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void		setEmpty()											{ CLPoint3 p(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);	m_Min = -p; m_Max = p;}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Setups a point AABB.
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void		setPoint(const CLPoint3& pt)							{ m_Min = m_Max = pt;												}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Gets the size of the AABB. The size is defined as the longest extent.
	*	\return		the size of the AABB
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	float		getSize()								const		{ CLPoint3 e; getExtents(e);	return e.Max();	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Extends the AABB.
	*	\param		p	[in] the next point
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void		extend(const CLPoint3& p)
	{
		if(p.x > m_Max.x)	m_Max.x = p.x;
		if(p.x < m_Min.x)	m_Min.x = p.x;

		if(p.y > m_Max.y)	m_Max.y = p.y;
		if(p.y < m_Min.y)	m_Min.y = p.y;

		if(p.z > m_Max.z)	m_Max.z = p.z;
		if(p.z < m_Min.z)	m_Min.z = p.z;
	}
	// Data access

	//! Get min point of the box
	inline			void		getMin(CLPoint3& min)						const		{ min = m_Min;								}
	//! Get max point of the box
	inline			void		getMax(CLPoint3& max)						const		{ max = m_Max;								}

	//! Get min point of the box
	inline			CLPoint3		getMin( )						const		{ return m_Min;								}
	//! Get max point of the box
	inline			CLPoint3		getMax( )						const		{ return m_Max;								}


	//! Get component of the box's min point along a given axis
	inline			float		getMin(unsigned int axis)						const		{ return m_Min[axis];						}
	//! Get component of the box's max point along a given axis
	inline			float		getMax(unsigned int axis)						const		{ return m_Max[axis];						}

	//! Get box center
	inline			void		getCenter(CLPoint3& center)				const		{ center = (m_Max + m_Min)*0.5f;				}
	//! Get box extents
	inline			void		getExtents(CLPoint3& extents)				const		{ extents = (m_Max - m_Min)*0.5f;				}

	//! Get component of the box's center along a given axis
	inline			float		getCenter(unsigned int axis)					const		{ return (m_Max[axis] + m_Min[axis])*0.5f;	}
	//! Get component of the box's extents along a given axis
	inline			float		getExtents(unsigned int axis)					const		{ return (m_Max[axis] - m_Min[axis])*0.5f;	}

	//! Get box diagonal
	inline			void		getDiagonal(CLPoint3& diagonal)			const		{ diagonal = m_Max - m_Min;					}
	inline			float		getWidth()								const		{ return m_Max.x - m_Min.x;					}
	inline			float		getHeight()								const		{ return m_Max.y - m_Min.y;					}
	inline			float		getDepth()								const		{ return m_Max.z - m_Min.z;					}

	//! Volume
	inline			float		getVolume()								const		{ return getWidth() * getHeight() * getDepth();		}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Computes the intersection between two AABBs.
	*	\param		a		[in] the other AABB
	*	\return		true on intersection
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	inline			bool		intersect(const CLAABB& a)				const
	{
		if(m_Max.x < a.m_Min.x
			|| a.m_Max.x < m_Min.x
			|| m_Max.y < a.m_Min.y
			|| a.m_Max.y < m_Min.y
			|| m_Max.z < a.m_Min.z
			|| a.m_Max.z < m_Min.z)	return false;

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Computes the intersection between a AABB and a Point.
	*	\param		a		[in] the other AABB
	*	\return		true on intersection
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	inline			bool		intersect(const CLPoint3& v)				const
	{
		if(m_Max.x < v.x
			|| v.x < m_Min.x
			|| m_Max.y < v.y
			|| v.y < m_Min.y
			|| m_Max.z < v.z
			|| v.z < m_Min.z)	return false;

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Computes the 1D-intersection between two AABBs, on a given axis.
	*	\param		a		[in] the other AABB
	*	\param		axis	[in] the axis (0, 1, 2)
	*	\return		true on intersection
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	inline			bool		intersect(const CLAABB& a, unsigned int axis)	const
	{
		if(m_Max[axis] < a.m_Min[axis] || a.m_Max[axis] < m_Min[axis])	return false;
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	To see if the box intersect with the giving ray.
	*	\param		ray		[in] giving ray
	*	\return		true on intersection
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	inline	bool intersect( const CLRay& ray ) const
	{
		float lowt = 0.0f;
		float t;
		bool hit = false;
		CLPoint3 hitpoint;
		CLPoint3 min,max;
		getMin(min);
		getMax(max);
		const CLPoint3& rayorig = ray.mOrig;
		const CLPoint3& raydir = ray.mDir;

		// Check origin inside first
		if ( rayorig > min && rayorig < max )
		{
			return true;
		}

		// Check each face in turn, only check closest 3
		// Min x
		if (rayorig.x < min.x && raydir.x > 0)
		{
			t = (min.x - rayorig.x) / raydir.x;
			if (t > 0)
			{
				// Substitute t back into ray and check bounds and dist
				hitpoint = rayorig + raydir * t;
				if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
					hitpoint.z >= min.z && hitpoint.z <= max.z &&
					(!hit || t < lowt))
				{
					hit = true;
					lowt = t;
				}
			}
		}
		// Max x
		if (rayorig.x > max.x && raydir.x < 0)
		{
			t = (max.x - rayorig.x) / raydir.x;
			if (t > 0)
			{
				// Substitute t back into ray and check bounds and dist
				hitpoint = rayorig + raydir * t;
				if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
					hitpoint.z >= min.z && hitpoint.z <= max.z &&
					(!hit || t < lowt))
				{
					hit = true;
					lowt = t;
				}
			}
		}
		// Min y
		if (rayorig.y < min.y && raydir.y > 0)
		{
			t = (min.y - rayorig.y) / raydir.y;
			if (t > 0)
			{
				// Substitute t back into ray and check bounds and dist
				hitpoint = rayorig + raydir * t;
				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
					hitpoint.z >= min.z && hitpoint.z <= max.z &&
					(!hit || t < lowt))
				{
					hit = true;
					lowt = t;
				}
			}
		}
		// Max y
		if (rayorig.y > max.y && raydir.y < 0)
		{
			t = (max.y - rayorig.y) / raydir.y;
			if (t > 0)
			{
				// Substitute t back into ray and check bounds and dist
				hitpoint = rayorig + raydir * t;
				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
					hitpoint.z >= min.z && hitpoint.z <= max.z &&
					(!hit || t < lowt))
				{
					hit = true;
					lowt = t;
				}
			}
		}
		// Min z
		if (rayorig.z < min.z && raydir.z > 0)
		{
			t = (min.z - rayorig.z) / raydir.z;
			if (t > 0)
			{
				// Substitute t back into ray and check bounds and dist
				hitpoint = rayorig + raydir * t;
				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
					hitpoint.y >= min.y && hitpoint.y <= max.y &&
					(!hit || t < lowt))
				{
					hit = true;
					lowt = t;
				}
			}
		}
		// Max z
		if (rayorig.z > max.z && raydir.z < 0)
		{
			t = (max.z - rayorig.z) / raydir.z;
			if (t > 0)
			{
				// Substitute t back into ray and check bounds and dist
				hitpoint = rayorig + raydir * t;
				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
					hitpoint.y >= min.y && hitpoint.y <= max.y &&
					(!hit || t < lowt))
				{
					hit = true;
					lowt = t;
				}
			}
		}

		return hit;

	}


	//////////////////////////////////////////////////////////////////////////
	/**
	*	To see if the box intersect with the giving ray.
	*	\param		vStart		[in] start point
	*	\param		vEnd		[in] end point
	*	\param		outNormal	[out] out normal (optional)
	*	\return		Returns point of intersection in range 0...1 or relly big number 
	*/
	//////////////////////////////////////////////////////////////////////////
	float		intersect( const CLPoint3 &vStart, const CLPoint3 &vEnd, CLPoint3 &outNormal );


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Recomputes the AABB after an arbitrary transform by a 4x4 matrix.
	*	Original code by Charles Bloom on the GD-Algorithm list. (I slightly modified it)
	*	\param		mtx			[in] the transform matrix
	*	\param		aabb		[out] the transformed AABB [can be *this]
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	inline			void		rotate(const CLMatrix4x4& mtx, CLAABB& aabb)	const
	{
		// The three edges transformed: you can efficiently transform an X-only vector
		// by just getting the "X" column of the matrix
		CLPoint3 vx,vy,vz;
		mtx.getRow(0, vx);	vx *= (m_Max.x - m_Min.x);
		mtx.getRow(1, vy);	vy *= (m_Max.y - m_Min.y);
		mtx.getRow(2, vz);	vz *= (m_Max.z - m_Min.z);

		// Transform the min point
		CLPoint3 ptMul;
		LM_Mul( mtx, m_Min, ptMul );
		aabb.m_Min = aabb.m_Max = ptMul;

		// Take the transformed min & axes and find new extents
		// Using CPU code in the right place is faster...
		if(IS_NEGATIVE_FLOAT(vx.x))	aabb.m_Min.x += vx.x; else aabb.m_Max.x += vx.x;
		if(IS_NEGATIVE_FLOAT(vx.y))	aabb.m_Min.y += vx.y; else aabb.m_Max.y += vx.y;
		if(IS_NEGATIVE_FLOAT(vx.z))	aabb.m_Min.z += vx.z; else aabb.m_Max.z += vx.z;
		if(IS_NEGATIVE_FLOAT(vy.x))	aabb.m_Min.x += vy.x; else aabb.m_Max.x += vy.x;
		if(IS_NEGATIVE_FLOAT(vy.y))	aabb.m_Min.y += vy.y; else aabb.m_Max.y += vy.y;
		if(IS_NEGATIVE_FLOAT(vy.z))	aabb.m_Min.z += vy.z; else aabb.m_Max.z += vy.z;
		if(IS_NEGATIVE_FLOAT(vz.x))	aabb.m_Min.x += vz.x; else aabb.m_Max.x += vz.x;
		if(IS_NEGATIVE_FLOAT(vz.y))	aabb.m_Min.y += vz.y; else aabb.m_Max.y += vz.y;
		if(IS_NEGATIVE_FLOAT(vz.z))	aabb.m_Min.z += vz.z; else aabb.m_Max.z += vz.z;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	Checks the AABB is valid.
	*	\return		true if the box is valid
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	inline			bool		isValid()	const
	{
		// Consistency condition for (Min, Max) boxes: min < max
		if(m_Min.x > m_Max.x)	return false;
		if(m_Min.y > m_Max.y)	return false;
		if(m_Min.z > m_Max.z)	return false;
		return true;
	}

	//! Operator for AABB *= float. Scales the extents, keeps same center.
	inline			CLAABB&		operator*=(float s)
	{
		CLPoint3 Center;	getCenter(Center);
		CLPoint3 Extents;	getExtents(Extents);
		setCenterExtents(Center, Extents * s);
		return *this;
	}

	//! Operator for AABB /= float. Scales the extents, keeps same center.
	inline			CLAABB&		operator/=(float s)
	{
		CLPoint3 Center;	getCenter(Center);
		CLPoint3 Extents;	getExtents(Extents);
		setCenterExtents(Center, Extents / s);
		return *this;
	}

	//! Operator for AABB += Point. Translates the box.
	inline			CLAABB&		operator+=(const CLPoint3& trans)
	{
		m_Min+=trans;
		m_Max+=trans;
		return *this;
	}

	//! Operator for AABB += AABB. Extend the box.
	inline			CLAABB&		operator+=( const CLAABB& box )
	{
		m_Min.x = box.m_Min.x > m_Min.x ? m_Min.x : box.m_Min.x;
		m_Min.y = box.m_Min.y > m_Min.y ? m_Min.y : box.m_Min.y;
		m_Min.z = box.m_Min.z > m_Min.z ? m_Min.z : box.m_Min.z;

		m_Max.x = box.m_Max.x < m_Max.x ? m_Max.x : box.m_Max.x;
		m_Max.y = box.m_Max.y < m_Max.y ? m_Max.y : box.m_Max.y;
		m_Max.z = box.m_Max.z < m_Max.z ? m_Max.z : box.m_Max.z;
		return *this;
	}

public:
	CLPoint3		m_Min;			//!< Min point
	CLPoint3		m_Max;			//!< Max point

};

//#else

//class  LABORCORE_API CLAABB
//{
//public:
//	//! Constructor
//	inline						CLAABB()	{}
//	//! Destructor
//	inline						~CLAABB()	{}
//
//	//! Type-independent methods
//	AABB_COMMON_METHODS;
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Setups an AABB from min & max vectors.
//	*	\param		min			[in] the min point
//	*	\param		max			[in] the max point
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	void		setMinMax(const CLPoint3& min, const CLPoint3& max)		{ mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f;		}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Setups an AABB from center & extents vectors.
//	*	\param		c			[in] the center point
//	*	\param		e			[in] the extents vector
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	void		setCenterExtents(const CLPoint3& c, const CLPoint3& e)	{ mCenter = c;	 mExtents = e;									}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Setups an empty AABB.
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	void		setEmpty()											{ mCenter.zero(); mExtents.set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Setups a point AABB.
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	void		setPoint(const CLPoint3& pt)							{ mCenter = pt; mExtents.zero();								}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Gets the size of the AABB. The size is defined as the longest extent.
//	*	\return		the size of the AABB
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	float		getSize()								const		{ return mExtents.Max();					}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Extends the AABB.
//	*	\param		p	[in] the next point
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	void		extend(const CLPoint3& p)
//	{
//		CLPoint3 Max = mCenter + mExtents;
//		CLPoint3 Min = mCenter - mExtents;
//
//		if(p.x > Max.x)	Max.x = p.x;
//		if(p.x < Min.x)	Min.x = p.x;
//
//		if(p.y > Max.y)	Max.y = p.y;
//		if(p.y < Min.y)	Min.y = p.y;
//
//		if(p.z > Max.z)	Max.z = p.z;
//		if(p.z < Min.z)	Min.z = p.z;
//
//		setMinMax(Min, Max);
//	}
//	// Data access
//
//	//! Get min point of the box
//	inline			void		getMin(CLPoint3& min)						const		{ min = mCenter - mExtents;					}
//	//! Get max point of the box
//	inline			void		getMax(CLPoint3& max)						const		{ max = mCenter + mExtents;					}
//
//	//! Get component of the box's min point along a given axis
//	inline			float		getMin(unsigned int axis)						const		{ return mCenter[axis] - mExtents[axis];	}
//	//! Get component of the box's max point along a given axis
//	inline			float		getMax(unsigned int axis)						const		{ return mCenter[axis] + mExtents[axis];	}
//
//	//! Get box center
//	inline			void		getCenter(CLPoint3& center)				const		{ center = mCenter;							}
//	//! Get box extents
//	inline			void		getExtents(CLPoint3& extents)				const		{ extents = mExtents;						}
//
//	//! Get component of the box's center along a given axis
//	inline			float		getCenter(unsigned int axis)					const		{ return mCenter[axis];						}
//	//! Get component of the box's extents along a given axis
//	inline			float		getExtents(unsigned int axis)					const		{ return mExtents[axis];					}
//
//	//! Get box diagonal
//	inline			void		getDiagonal(CLPoint3& diagonal)			const		{ diagonal = mExtents * 2.0f;				}
//	inline			float		getWidth()								const		{ return mExtents.x * 2.0f;					}
//	inline			float		getHeight()								const		{ return mExtents.y * 2.0f;					}
//	inline			float		getDepth()								const		{ return mExtents.z * 2.0f;					}
//
//	//! Volume
//	inline			float		getVolume()								const		{ return mExtents.x * mExtents.y * mExtents.z * 8.0f;	}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Computes the intersection between two AABBs.
//	*	\param		a		[in] the other AABB
//	*	\return		true on intersection
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	inline			bool		intersect(const CLAABB& a)				const
//	{
//		float tx = mCenter.x - a.mCenter.x;	float ex = a.mExtents.x + mExtents.x;	if(AIR(tx) > IR(ex))	return false;
//		float ty = mCenter.y - a.mCenter.y;	float ey = a.mExtents.y + mExtents.y;	if(AIR(ty) > IR(ey))	return false;
//		float tz = mCenter.z - a.mCenter.z;	float ez = a.mExtents.z + mExtents.z;	if(AIR(tz) > IR(ez))	return false;
//		return true;
//	}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	The standard intersection method from Gamasutra. Just here to check its speed against the one above.
//	*	\param		a		[in] the other AABB
//	*	\return		true on intersection
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	inline			bool		gomezIntersect(const CLAABB& a)
//	{
//		CLPoint3	T = mCenter - a.mCenter;	// Vector from A to B
//		return	((fabsf(T.x) <= (a.mExtents.x + mExtents.x))
//			&& (fabsf(T.y) <= (a.mExtents.y + mExtents.y))
//			&& (fabsf(T.z) <= (a.mExtents.z + mExtents.z)));
//	}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Computes the 1D-intersection between two AABBs, on a given axis.
//	*	\param		a		[in] the other AABB
//	*	\param		axis	[in] the axis (0, 1, 2)
//	*	\return		true on intersection
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	inline			bool		intersect(const CLAABB& a, unsigned int axis)	const
//	{
//		float t = mCenter[axis] - a.mCenter[axis];
//		float e = a.mExtents[axis] + mExtents[axis];
//		if(AIR(t) > IR(e))	return false;
//		return true;
//	}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	To see if the box intersect with the giving ray.
//	*	\param		ray		[in] giving ray
//	*	\return		true on intersection
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	inline			bool		intersect(const CLRay& ray) const
//	{
//		//if( IsEmpty() )
//		//	return false;
//
//		CLPoint3 low, high; 
//		const CLPoint3& rayPos = ray.mOrig;
//		const CLPoint3& rayDir = ray.mDir;
//		getMin( low );
//		getMax( high );
//
//
//		float r;
//		float te;
//		float tl;
//
//		float in  = 0.f;
//		float out = Inf;
//
//		float xDir = rayDir[0];
//		float xPos = rayPos[0];
//
//		if(xDir > Eps || xDir < -Eps)
//		{
//			r = 1.f / xDir;
//
//			if(xDir > 0.f)
//			{
//				te = (low [0] - xPos) * r;
//				tl = (high[0] - xPos) * r;
//			}
//			else
//			{
//				te = (high[0] - xPos) * r;
//				tl = (low [0] - xPos) * r;
//			}
//
//			// check for flat boxes, count them as intersected
//			if(tl-te < Eps)        
//				return true;
//
//			//        if (te > 1)   return false;
//
//			if(tl < out)   
//				out = tl;
//
//			if(te > in)    
//				in  = te;
//		}
//		else if(xPos < low[0] || xPos > high[0])
//		{
//			return false;
//		}
//
//
//		float yDir = rayDir[1];
//		float yPos = rayPos[1];
//		if(yDir > Eps || yDir < -Eps)
//		{
//			r = 1.f / yDir;
//
//			if(yDir > 0.f)
//			{
//				te = (low [1] - yPos) * r;
//				tl = (high[1] - yPos) * r;
//			}
//			else
//			{
//				te = (high[1] - yPos) * r;
//				tl = (low [1] - yPos) * r;
//			}
//
//			// check for flat boxes, count them as intersected
//			if(tl-te < Eps)        
//				return true;
//
//			//        if (te > 1)   return false;
//
//			if(tl < out)   
//				out = tl;
//
//			if(te > in)    
//				in  = te;
//		}
//		else if(yPos < low[1] || yPos > high[1])
//		{
//			return false;
//		}
//
//
//		float zDir = rayDir[2];
//		float zPos = rayPos[2];
//		if(zDir > Eps || zDir < -Eps)
//		{
//			r = 1.f / zDir;
//
//			if(zDir > 0.f)
//			{
//				te = (low [2] - zPos) * r;
//				tl = (high[2] - zPos) * r;
//			}
//			else
//			{
//				te = (high[2] - zPos) * r;
//				tl = (low [2] - zPos) * r;
//			}
//
//			// check for flat boxes, count them as intersected
//			if(tl-te < Eps)        
//				return true;
//
//			//        if (te > 1)   return false;
//
//			if(tl < out)   
//				out = tl;
//
//			if(te > in)    
//				in  = te;
//		}
//		else if(zPos < low[2] || zPos > high[2])
//		{
//			return false;
//		}
//
//		enter = in;
//		exit  = out;
//
//		if(enter > exit)
//			return false;
//
//		return true;
//
//	}
//
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Recomputes the AABB after an arbitrary transform by a 4x4 matrix.
//	*	\param		mtx			[in] the transform matrix
//	*	\param		aabb		[out] the transformed AABB [can be *this]
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	inline			void		rotate(const CLMatrix4x4& mtx, CLAABB& aabb)	const
//	{
//		// Compute new center
//		aabb.mCenter = mCenter * mtx;
//
//		// Compute new extents. FPU code & CPU code have been interleaved for improved performance.
//		CLPoint3 Ex(mtx.m[0][0] * mExtents.x, mtx.m[0][1] * mExtents.x, mtx.m[0][2] * mExtents.x);
//		IR(Ex.x)&=0x7fffffff;	IR(Ex.y)&=0x7fffffff;	IR(Ex.z)&=0x7fffffff;
//
//		CLPoint3 Ey(mtx.m[1][0] * mExtents.y, mtx.m[1][1] * mExtents.y, mtx.m[1][2] * mExtents.y);
//		IR(Ey.x)&=0x7fffffff;	IR(Ey.y)&=0x7fffffff;	IR(Ey.z)&=0x7fffffff;
//
//		CLPoint3 Ez(mtx.m[2][0] * mExtents.z, mtx.m[2][1] * mExtents.z, mtx.m[2][2] * mExtents.z);
//		IR(Ez.x)&=0x7fffffff;	IR(Ez.y)&=0x7fffffff;	IR(Ez.z)&=0x7fffffff;
//
//		aabb.mExtents.x = Ex.x + Ey.x + Ez.x;
//		aabb.mExtents.y = Ex.y + Ey.y + Ez.y;
//		aabb.mExtents.z = Ex.z + Ey.z + Ez.z;
//	}
//
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	/**
//	*	Checks the AABB is valid.
//	*	\return		true if the box is valid
//	*/
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	inline			bool		isValid()	const
//	{
//		// Consistency condition for (Center, Extents) boxes: Extents >= 0
//		if(IS_NEGATIVE_FLOAT(mExtents.x))	return false;
//		if(IS_NEGATIVE_FLOAT(mExtents.y))	return false;
//		if(IS_NEGATIVE_FLOAT(mExtents.z))	return false;
//		return true;
//	}
//
//	//! Operator for AABB *= float. Scales the extents, keeps same center.
//	inline			CLAABB&		operator*=(float s)		{ mExtents*=s;	return *this;	}
//
//	//! Operator for AABB /= float. Scales the extents, keeps same center.
//	inline			CLAABB&		operator/=(float s)		{ mExtents/=s;	return *this;	}
//
//	//! Operator for AABB += Point. Translates the box.
//	inline			CLAABB&		operator+=(const CLPoint3& trans)
//	{
//		mCenter+=trans;
//		return *this;
//	}
//private:
//	CLPoint3		mCenter;			//!< AABB Center
//	CLPoint3		mExtents;			//!< x, y and z extents
//
//};

//#endif

inline void computeMinMax(const CLPoint3& p, CLPoint3& min, CLPoint3& max)
{
	if(p.x > max.x)	max.x = p.x;
	if(p.x < min.x)	min.x = p.x;

	if(p.y > max.y)	max.y = p.y;
	if(p.y < min.y)	min.y = p.y;

	if(p.z > max.z)	max.z = p.z;
	if(p.z < min.z)	min.z = p.z;
}

inline void computeAABB(CLAABB& aabb, const CLPoint3* list, unsigned int nb_pts)
{
	if(list)
	{
		CLPoint3 Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
		CLPoint3 Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT);
		while(nb_pts--)
		{
			//				_prefetch(list+1);	// off by one ?
			computeMinMax(*list++, Mini, Maxi);
		}
		aabb.setMinMax(Mini, Maxi);
	}
}

NAMESPACE_LABOR3D_END
#endif	// __LABORAABB_H__
